import concurrent.futures
import threading
import time
from collections import deque

import requests
from faker import Faker
from loguru import logger as log

from utils.proxies_tools import get_company_ip_crawler_by_api
from utils.tools import get_md5


class InMemoryRateLimiter:
    def __init__(self, max_calls: int, period: float):
        self.max_calls = max_calls
        self.period = period
        self.lock = threading.Lock()
        self.calls = deque()

    def allow_request(self) -> bool:
        with self.lock:
            now = time.time()
            while self.calls and self.calls[0] <= now - self.period:
                self.calls.popleft()

            if len(self.calls) < self.max_calls:
                self.calls.append(now)
                return True
            else:
                return False

    def wait_until_allowed(self):
        while not self.allow_request():
            time.sleep(0.05)


class PatentNormalUser:
    def __init__(self, cookies=None, user_agent=None, proxies=None, rate_limit=2, **kwargs):
        self.user_agent = user_agent
        self.proxies = proxies
        self.cookies = cookies
        self.user_id = kwargs.get("user_id") or get_md5(user_agent, proxies, cookies)
        self.session = requests.Session()
        self.logged_in = self.login()
        self.rate_limiter = InMemoryRateLimiter(max_calls=1, period=rate_limit)  # 限制：每2秒最多1次请求

    def login(self):
        headers = {"User-Agent": self.user_agent}
        try:
            self.session.get("http://epub.cnipa.gov.cn", headers=headers, proxies=self.proxies, timeout=5)
            return True  # 可根据返回数据进一步判断登录是否成功
        except Exception as e:
            log.debug(f"[Login Error] {self.proxies.get('http')}: {e}")
            return False

    def is_ready(self, _ignored_rate_limit):
        return self.logged_in and self.rate_limiter.allow_request()

    def wait_until_ready(self):
        self.rate_limiter.wait_until_allowed()


class PatentNormalUserPool:
    def __init__(self, rate_limit=4, min_users=10):
        self.rate_limit = rate_limit
        self.min_users = min_users
        self.users = []
        self.lock = threading.Lock()

    def add_new_user(self):
        proxies = get_company_ip_crawler_by_api()
        proxy = proxies.get("http") or ""
        user_id = proxy.split("@")[-1]
        if not (user_id in [i.user_id for i in self.users]):
            user = PatentNormalUser(
                user_agent=Faker().user_agent(),
                proxies=proxies,
                user_id=user_id,
                rate_limit=self.rate_limit
            )
            if user.logged_in:
                self.users.append(user)
                log.debug(f"[PatentNormalUserPool] Added user: {user_id}")
            else:
                log.debug(f"[PatentNormalUserPool] Login failed for: {user_id}")

    def _maintain_user_pool(self):
        # 清理失效用户
        self.users = [u for u in self.users if u.logged_in]
        while len(self.users) < self.min_users:
            log.info(f"当前在线user数为 {len(self.users)} 小于 {self.min_users}, 生产user")
            self.add_new_user()
            time.sleep(1)

    def get_available_user(self):
        for user in self.users:
            if user.is_ready(self.rate_limit):
                return user
        return None

    def get_user(self):
        with self.lock:
            self._maintain_user_pool()
            user = self.get_available_user()

        while not user:
            log.info("[PatentNormalUserPool] No available user, waiting...")
            time.sleep(1)
            with self.lock:
                self._maintain_user_pool()
                user = self.get_available_user()

        log.info(f"[PatentNormalUserPool] Using {user.user_id}")
        user.wait_until_ready()
        return user

    def del_user(self, user_id):
        log.info(f"del {user_id}")
        new_users = []
        for i in self.users:
            if i.user_id != user_id:
                new_users.append(i)
        self.users = new_users
